package com.llm.travel_agent_assistant.service.impl;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.RandomUtil;
import com.llm.travel_agent_assistant.dto.BudgetAnalyzeDTO;
import com.llm.travel_agent_assistant.dto.GeneratePlanDTO;
import com.llm.travel_agent_assistant.dto.QuestionDTO;
import com.llm.travel_agent_assistant.dto.Result;
import com.llm.travel_agent_assistant.entity.BudgetAnalyze;
import com.llm.travel_agent_assistant.entity.TravelPlan;
import com.llm.travel_agent_assistant.mapper.BudgetAnalyzeMapper;
import com.llm.travel_agent_assistant.mapper.TravelPlanMapper;
import com.llm.travel_agent_assistant.service.OpenAiService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import opennlp.tools.util.StringUtil;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Flux;

import javax.validation.constraints.Size;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@Service
public class OpenAiServiceImpl implements OpenAiService {

    @Resource
    @Qualifier("deepSeekClient")
    private ChatClient chatClient;
    @Resource
    private TravelPlanMapper travelPlanMapper;
    @Resource
    private BudgetAnalyzeMapper budgetAnalyzeMapper;

    @Override
    public Result generateTravelPlan(GeneratePlanDTO generatePlanDTO) {
        String systemPrompt = String.format("""
                **前提**: 你是一个资深的导游，熟悉世界各国著名旅游景点，擅长指定旅游计划
                
                **当前用户需求**: %s
                
                **分析用户需求:**
                请深入分析用户的具体需求，制定明确且详细的旅游计划：
                1. 如果用户输入的内容跟旅游无关，那么不做以下处理，直接只返回标识 [NOT_TRAVEL_RELEVANT_QUESTION]，其余信息都不返回
                2. 理解用户真正想要表达的信息（如：旅行目的地、日期、预算、同行人数、旅行偏好等）
                3. 获取旅行目的地的相关景点信息，做一个大概 200 字左右的简单总结
                4. 根据用户表达的信息，制定对应的旅行计划 (包括交通、住宿、景点、餐厅等详细信息)
                5. 旅行计划详细信息
                    5.1 对于交通，需要给出交通方式的建议，并说明大概花费多少钱
                    5.2 对于住宿，需要给出住宿的酒店名称，地点，并说明大概花费多少钱
                    5.3 对于景点，需要给出景点的名称，地点，以及使用何种交通方式，并根据同行人数计算大概花费多少钱
                    5.4 对于餐厅，需要给出餐厅的名称，地点，并根据同行人数计算大概花费多少钱
                6. 对制定的旅行计划，分析是否能够满足用户需求(如预算是否足够)，如果不行则进行改进
                
                **输出格式要求:**
                旅行计划名称: [旅行目的地_旅行计划]
                行程规划: 根据指定的旅行计划详细信息，列出行程规划(包括到达哪个景点，什么时间点去，使用的交通方式，大概花费)，按照 DAY1 到 DAYn 列出来
                住宿: 根据行程规划，选定合适的地点住宿
                餐厅: 根据行程规划，选定合适的餐厅，或者根据景点当地特色美食进推荐
                
                **注意:**
                    输出格式严格按照 **输出格式要求:** 要求来，其他多余信息不要输出
                """, generatePlanDTO.getMessage());
        String travelPlan = chatClient.prompt(systemPrompt).call().content();

        // 如果不是旅游相关问题，直接返回
        if (travelPlan != null && travelPlan.contains("NOT_TRAVEL_RELEVANT_QUESTION")) {
            return Result.fail("我只是一名旅行助手，很抱歉无法回答其他问题");
        }
        // 把解析后的计划存到数据库
        String parsedTravelPlan = parseTravelPlan(travelPlan);
        String planName = getPlanName(parsedTravelPlan);

        // 去掉计划名称的中括号
        parsedTravelPlan = parsedTravelPlan.replace("[", "");
        parsedTravelPlan = parsedTravelPlan.replace("]", "");

        TravelPlan plan = new TravelPlan();
        plan.setPlanId(RandomUtil.randomNumbers(20));
        plan.setPlanName(planName);
        plan.setPlanContent(parsedTravelPlan);
        plan.setCreateTime(LocalDateTime.now());
        plan.setOwnerId(generatePlanDTO.getOwnerId());
        travelPlanMapper.insert(plan);
        // 直接返回 ok 让用户去计划列表查看最新计划
        return Result.ok();
    }

    @Override
    public Result budgetAnalyze(BudgetAnalyzeDTO budgetAnalyzeDTO) {
        String systemPrompt = String.format("""
                **前提**: 你是一个资深的导游，熟悉世界各国著名旅游景点，擅长指定旅游计划
                         同时，你也是一个资深的费用预算分析师，擅长分析各种开销、花费预算；
                         用户去旅游的同时，可能会买一些纪念品或者其他商品；
                         请你根据用户需求分析费用预算。
                
                **当前用户需求**: %s
                
                **分析用户需求:**
                请深入分析用户的具体需求，制定明确且详细的旅游计划：
                1. 如果用户输入的内容跟旅游无关，那么不做以下处理，直接只返回标识 [NOT_BUDGET_ANALYZE_QUESTION]，其余信息都不返回
                2. 理解用户真正想要表达的信息（如：旅行目的地、日期、预算、同行人数、旅行偏好等）
                3. 根据用户表达的信息，制定对应的旅行计划 (包括交通、住宿、景点、餐厅等详细信息)
                4. 你可以给用户推荐纪念品，并说明大概花费多少钱，不需要很精确，一个大概就行
                5. 旅行计划详细信息
                    5.1 对于交通，需要给出交通方式的建议，并说明大概花费多少钱
                    5.2 对于住宿，需要给出住宿的酒店名称，地点，并说明大概花费多少钱
                    5.3 对于景点，需要给出景点的名称，地点，并根据同行人数计算大概花费多少钱
                    5.4 对于餐厅，需要给出餐厅的名称，地点，并根据同行人数计算大概花费多少钱
                    5.5 
                6. 对制定的旅行计划，总结计算所有的花费是多少钱
                
                **输出格式要求:**
                费用预算分析名称: [旅行目的地_费用预算分析]
                预算明细: 在旅行计划详细信息中的所有费用明细，注意分点列出，可参考以下格式:
                            ~ 交通:
                                - 国际航班: 往返经济舱(中国->东京)，约¥4000/人，总计¥8000
                                - 市内交通：
                                    * 地铁(72小时券): ¥150/人x5天≈¥750/人，总计¥1500
                                    * ...
                            ~ 住宿:
                                - 酒店: 新宿格拉斯丽酒店(4星，新宿站附近) 双人间¥800/晚x4晚≈¥3200
                                - ...
                            ~ ...
                预算总费用: 最后总结计算所有的花费, 参考格式如下:
                          ¥8000(机票)+¥1900(交通)+¥1200(周边)+¥3200(住宿)+¥1800(景点)+¥2800(餐饮)=¥18900

                **注意:**
                    输出格式严格按照 **输出格式要求:** 要求来，其他多余信息不要输出
                """, budgetAnalyzeDTO.getMessage());
        String budgetAnalyze = chatClient.prompt(systemPrompt).call().content();
        if (budgetAnalyze != null && budgetAnalyze.contains("NOT_BUDGET_ANALYZE_QUESTION")) {
            return Result.fail("我只是一名预算分析助手，很抱歉无法回答其他问题");
        }

        String parseBudgetAnalyze = parseBudgetAnalyze(budgetAnalyze);
        String budgetAnalyzeName = getPlanName(parseBudgetAnalyze);

        // 去掉名称的中括号
        parseBudgetAnalyze = parseBudgetAnalyze.replace("[", "");
        parseBudgetAnalyze = parseBudgetAnalyze.replace("]", "");

        // 保存
        BudgetAnalyze analyze = new BudgetAnalyze();
        analyze.setAnalyzeId(RandomUtil.randomNumbers(20));
        analyze.setAnalyzeName(budgetAnalyzeName);
        analyze.setCreateTime(LocalDateTime.now());
        analyze.setAnalyzeContent(parseBudgetAnalyze);
        analyze.setOwnerId(budgetAnalyzeDTO.getUserId());
        budgetAnalyzeMapper.insert(analyze);
        // 直接返回 ok 让用户去预算分析列表查看最新分析
        return Result.ok();
    }

    @Override
    public Result solveAnyQuestion(QuestionDTO questionDTO) {
        String systemPrompt = String.format("""
                **前提:** 你是一个万能的生活小助手，对于旅游、安全(比如遇到危险该怎么处理)、地理(熟悉世界各国的城市、地理信息)特别的擅长
                
                ** 当前用户需求: ** %s
                **分析用户需求:**
                    1.深度理解用户的需求，对需求进行细致的分析
                    2.根据用户表达需求，以及你的分析，给出合理的解决方案
                ** 输出格式: **
                    需求分析: 对用户需求的细致分析
                    解决方案: 在分析阶段你所给出的解决方案，可以分点列出
                ** 注意: **
                    输出要求严格按照输出格式来
                """, questionDTO.getQuestion());

        String content = chatClient.prompt(systemPrompt).call().content();
        return Result.ok(parseAnyQuestion(content));
    }

    private String parseAnyQuestion(String content) {
        log.info("content: {}", content);
        String[] split = content.split("\n");

        StringBuilder sectionContent = new StringBuilder();

        for (String line : split) {
            line = line.replace("###", "");
            line = line.replace("**", "");
            line = line.trim();
            if (StringUtil.isEmpty(line)) {
            } else if (line.contains("需求分析")) {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            } else if (line.contains("解决方案")) {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            } else {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            }
        }
        return sectionContent.toString();
    }

    private String parseBudgetAnalyze(String budgetAnalyze) {
        log.info("parseBudgetAnalyze: {}", budgetAnalyze);
        String[] split = budgetAnalyze.split("\n");

        StringBuilder sectionContent = new StringBuilder();

        for (String line : split) {
            line = line.replace("###", "");
            line = line.replace("**", "");
            line = line.trim();
            if (StringUtil.isEmpty(line)) {
            } else if (line.contains("费用预算分析名称")) {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            } else if (line.contains("预算明细")) {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            } else if (line.contains("预算总费用")) {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            } else {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            }
        }
        return sectionContent.toString();
    }

    private String parseTravelPlan(String travelPlan){
        log.info("parseTravelPlan: {}", travelPlan);
        String[] split = travelPlan.split("\n");

        StringBuilder sectionContent = new StringBuilder();

        for (String line : split) {
            line = line.replace("###", "");
            line = line.replace("**", "");
            line = line.trim();
            if (StringUtil.isEmpty(line)) {
            } else if (line.contains("旅行计划名称")) {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            } else if (line.contains("旅行目的地相关景点")) {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            } else if (line.contains("交通方式")) {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            } else if (line.contains("住宿")) {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            } else if (line.contains("餐厅")) {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            } else {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            }
        }
        return sectionContent.toString().trim();
    }

    public String getPlanName(String str) {
        // 正则匹配：找出第一个 [ ... ] 中的内容
        Pattern pattern = Pattern.compile("\\[(.*?)\\]");
        Matcher matcher = pattern.matcher(str);

        if (matcher.find()) {
            return matcher.group(1); // group(1) 是 [] 中的内容
        } else {
            return ""; // 或者抛异常
        }
    }
}
